﻿using System;
using System.Diagnostics;

namespace Microsoft.Goldenlight.Framework
{
    /// <summary>
    /// 	Behavior can be added to GameObjects or other BehaviorContainer to provide pieces of re-usable functionality. Behavior are added to objects before being added to the object manager.
    /// </summary>
    /// <remarks>
    /// 	They are initialized and unitialized at the same time as the GameObject which contains them via the SetRegistered and SetUnregistered methods. BehaviorContainer can expose interfaces to all other behaviors inside the RegisterInterfaces method. The main reason for adding one behavior to another is to package them together for copying between multple objects. When a Behavior is added to another Behavior it behaves very much like it was simply added to the owning GameObject. When searching for an interface held by a behavior inside a behavior container, the search always begins at the owning GameObject, even if the behavior container is from a behavior not at the top level of the hierarchy. However, if using the FindBehavior method on a behavior container, it will search in that behavior container and all child containers only, so if using FindBehavior to look up behaviors, one can use the behavior hierarchy to scope the search.
    /// </remarks>
    public abstract class Behavior : LifetimeObject
    {
        #region Overrides of LifetimeObject

        #region Implementation of IDisposable

        /// <summary>
        /// 	Releases all resources used by the Game class.
        /// </summary>
        /// <param name="disposing"> true to release both managed and unmanaged resources; false to release only unmanaged resources. </param>
        protected override void Dispose(bool disposing)
        {
            _isDisposed = true;
            if (disposing)
            {
                if (_ownerObject != null)
                {
                    _ownerObject.RemoveBehavior(this);
                }
            }
            base.Dispose(disposing);
        }

        #endregion

        #endregion

        #region Owner Operations

        #region Fields & Properties

        private GameObject _ownerObject;

        /// <summary>
        /// 	Gets the associated owner object.
        /// </summary>
        /// <value> The owner object. </value>
        /// <remarks>
        /// 	Represents the object the instance is attached to.
        /// </remarks>
        public GameObject OwnerObject
        {
            get
            {
                return _ownerObject;
            }
        }

        /// <summary>
        /// 	Indicates if the behavior is attached to a object.
        /// </summary>
        public bool IsAttached
        {
            get
            {
                return _ownerObject != null;
            }
        }

        #endregion

        #region Attach & Detach

        /// <summary>
        /// 	Called after the behavior is attached to an OwnerObject.
        /// </summary>
        /// <remarks>
        /// 	Override this to hook up functionality to the OwnerObject.
        /// </remarks>
        protected virtual void OnAttach()
        {
        }

        /// <summary>
        /// 	Called when the behavior is being detached from its OwnerObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// 	Override this to unhook functionality from the OwnerObject.
        /// </remarks>
        protected virtual void OnDetach()
        {
        }

        /// <summary>
        /// 	Attaches to the specified object.
        /// </summary>
        /// <param name="ownerObject"> The object to attach to. </param>
        internal void Attach(GameObject ownerObject)
        {
            if (ownerObject != null && _ownerObject == null)
            {
                try
                {
                    _ownerObject = ownerObject;
                    OnAttach();
                }
                catch (Exception ex)
                {
                    //TODO: Trace
                    Debug.WriteLine(ex.Message);
                }
            }
        }

        /// <summary>
        /// 	Detaches this instance from its associated owner object.
        /// </summary>
        public void Detach()
        {
            if (_ownerObject != null)
            {
                try
                {
                    OnDetach();
                    _ownerObject = null;
                }
                catch (Exception ex)
                {
                    //TODO: Trace
                    Debug.WriteLine(ex.Message);
                }
            }
        }

        #endregion

        #endregion
    }
}